package org.jvm.nativemethod;


import org.jvm.nativemethod.methods.*;
import org.jvm.nativemethod.methods.java.io.*;
import org.jvm.nativemethod.methods.java.lang.*;
import org.jvm.nativemethod.methods.java.security.AccessControllerNativeMethod;
import org.jvm.nativemethod.methods.java.util.*;
import org.jvm.nativemethod.methods.java.util.concurrent.atomic.AtomicLongNativeMethod;
import org.jvm.nativemethod.methods.sun.io.Win32ErrorModeNativeMethod;
import org.jvm.nativemethod.methods.sun.misc.*;
import org.jvm.nativemethod.methods.sun.reflect.*;
import org.jvm.rtda.thread.Frame;

import java.lang.reflect.Method;
import java.util.*;

/**
 * @author 海燕
 * @date 2023/2/19
 */
public class NativeMethodRegister {

    public static final Map<String, Method> registry = new HashMap<>();

    static {
        try {
            FileDescriptorNativeMethod.init();
            FileOutputStreamNativeMethod.init();
            ClassNativeMethod.init();
            DoubleNativeMethod.init();
            FloatNativeMethod.init();
            ObjectNativeMethod.init();
            RuntimeNativeMethod.init();
            FileInputStreamMethod.init();
            JavaLangReflectArrayNativeMethod.init();
            StringNativeMethod.init();
            SystemNativeMethod.init();
            ThreadNativeMethod.init();
            ThrowableNativeMethod.init();
            PackageNativeMethod.init();
            AccessControllerNativeMethod.init();
            AtomicLongNativeMethod.init();
            Win32ErrorModeNativeMethod.init();
            ZipFileNativeMethod.init();
            SignalNativeMethod.init();
            JarFileNativeMethod.init();
            InflaterNativeMethod.init();
            VMNativeMethod.init();
            PerfNativeMethod.init();
            UnsafeNativeMethod.init();
            URLClassPathNativeMethod.init();
            NativeConstructorAccessorImplNativeMethod.init();
            ReflectionNativeMethod.init();
            MyNativeMethod.init();
            FileSystemNativeMethod.init();
            ClassLoaderNativeMethod.init();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    /**
     * 注册本地方法
     * 类名+方法名+方法描述指向唯一的本地方法
     *
     * @param className        Java中本地方法所在类
     * @param methodName       Java本地方法的名称
     * @param methodDescriptor Java本地方法的描述
     * @param nativeMethod     JVM中本地方法
     */
    public static void register(String className, String methodName, String methodDescriptor, Method nativeMethod) {
        String key = getKey(className, methodName, methodDescriptor);
        registry.put(key, nativeMethod);
    }

    /**
     * 查找本地方法
     *
     * @param className
     * @param methodName
     * @param methodDescriptor
     * @return
     */
    public static Method findNativeMethod(String className, String methodName, String methodDescriptor) {
        //跳过所有注册本地方法的方法，本地方法在本虚拟机中手动注册
        if ((methodName.equals("registerNatives") || methodName.equals("initIDs")) && methodDescriptor.equals("()V")) {
            try {
                return NativeMethod.class.getDeclaredMethod("emptyNativeMethod", Frame.class);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        String key = getKey(className, methodName, methodDescriptor);
        return registry.get(key);
    }

    private static String getKey(String className, String methodName, String methodDescriptor) {
        return className.concat("_").concat(methodName).concat("_").concat(methodDescriptor);
    }
}
